﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;


namespace NOS.Security
{
    public class DataHashTable
    {
        public DataHashTable(string ServiceName, string AssemblyPath, Assembly LoadedAssembly)
        {
            this.ServiceName = ServiceName;
            this.AssemblyPath = AssemblyPath;
            this.LoadedAssembly = LoadedAssembly;
        }

        public string ServiceName{ get; set; }

        public string AssemblyPath { get; set; }

        public Assembly LoadedAssembly { get; set; }               
    }
    
    public static class SafetyHashTable
    {
        private static Hashtable Hash = null;
        private static int AcessCount = 0;
        private static int ReadWaiter = 0;
        private static bool WaitExclusive = false;

        private static void Instance()
        {
            if (Hash == null)
            {
                Hash = new Hashtable();               
            }
        }

        public static Hashtable GetExclusive()
        {
            Trace.Write("Solicitado Acesso Excluivo ao Assembly Hash");
            Instance();
                 
            lock (Hash)
            {
                WaitExclusive = true;
                Trace.Write("Aguardando acesso Excluivo ao Assembly Hash");
                while(AcessCount != 0)
                {
                    Monitor.Wait(Hash);
                }
                Trace.Write("Concedido acesso Excluivo ao Assembly Hash");
                WaitExclusive = false;
                AcessCount = -1;
                return Hash;
            }
        }

        public static Hashtable GetShared()
        {
            Trace.Write("Solicitado Acesso compartilhado ao Assembly Hash");
            Instance();
            lock (Hash)
            {
                Trace.Write("Aguardando acesso compartilhado ao Assembly Hash");
                ReadWaiter++;
                while (AcessCount < 0 || WaitExclusive)
                {
                    Monitor.Wait(Hash);
                }
                Trace.Write("Concedido acesso compartilhado ao Assembly Hash");
                ReadWaiter--;
                AcessCount++;
                return Hash;
            }
        }

        public static void ReleaseExclusive()
        {
            Trace.Write("Liberando Acesso exlusivo");
            lock (Hash)
            {
                AcessCount = 0;
                if (ReadWaiter > 0)
                {
                    Monitor.PulseAll(Hash);
                }
                else
                {
                    if (Hash != null)
                    {
                        Monitor.Pulse(Hash);
                    }
                }
            }
        }

        public static void ReleaseShared()
        {
            Trace.Write("Liberando acesso compartilhado");
            lock (Hash)
            {
                AcessCount--;
                if (AcessCount == 0 && Hash != null)
                {
                    Monitor.Pulse(Hash);
                }
            }
        }
    }   
}